﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
using Advantech.Adam;
using System.Net.Sockets;

namespace MixingStation
{
    public partial class VideoControl : XtraUserControl
    {
        private string m_Title = "视频监控";
        //视频设备是否初始化成功
        private bool m_IsInitVideoSDK = false;
        //视频ID
        private int m_UserID = -1;
        //视频实时预览扩展句柄	1表示失败，其他值作为NET_DVR_StopRealPlay等函数的句柄参数
        private int m_RealHandle = -1;
        //频道数组
        private int[] m_ChannelNumArr = new int[96];
        //视频设备信息
        public CHCNetSDK.NET_DVR_DEVICEINFO_V30 m_VideoDeviceInfo;
        //视频参数
        private VideoParameter m_VideoParameter = null;
        //视频参数
        private GateControlParameter m_GateControlParameter = null;

        //初始化道闸IO
        private AdamSocket m_AdamSocket = null;

        public VideoControl()
        {
            InitializeComponent();
        }

        private void VideoControl_Load(object sender, EventArgs e)
        {
            timer_Clean.Interval = 30 * 60 * 1000;
        }

        #region 对外方法
        public void InitVideo(VideoParameter videoParameter, GateControlParameter gateControlParameter)
        {
            m_VideoParameter = videoParameter;
            m_GateControlParameter = gateControlParameter;
            if (videoParameter.IsShowVideo)
            {
                //视频处理
                try
                {
                    if (videoParameter.VideoType == 0)
                    {
                        InitVideoDevice();
                    }
                    timer_Clean.Enabled = true;
                    //默认初始化的时候打开视频
                    this.btnOpen_Click(null, null);
                }
                catch (Exception ex)
                {
                    string errInfo = "初始化" + m_Title + "异常：" + ex.Message;
                    MessageBox.Show(errInfo);
                    LogHelper.error(errInfo);
                }
            }
            else
            {
                this.btnOpen.Enabled = false;
                this.btnClose.Enabled = false;
            }
            if (gateControlParameter.GateWay >0)
            {
                if (gateControlParameter.GateWay == 1)
                {
                    lcgFGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Always;
                    lcgBGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
                }
                else if (gateControlParameter.GateWay == 1)
                {
                    lcgFGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
                    lcgBGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Always;
                }
                else if (gateControlParameter.GateWay == 2)
                {
                    lcgFGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Always;
                    lcgBGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Always;
                }

                //如果是IO控制道闸，则初始化IO
                if (gateControlParameter.GateControlWay == 1)
                {
                    try
                    {
                        m_AdamSocket.SetTimeout(1000, 1000, 1000);
                        m_AdamSocket.Connect(gateControlParameter.IpOfGateIO, ProtocolType.Tcp, 502);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.error("初始化道闸IO连接失败：" + ex.Message);
                        return;
                    }
                    timer_IOStatus.Enabled = true;
                }
            }
            else
            {
                lcgFGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
                lcgBGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
            }
        }

        //加载抓图
        public void LoadCapturePic(string fileName)
        {
            if (m_VideoParameter.VideoType == 0)
            {
                string dateStr = DateTime.Now.ToString("yyyyMMdd");
                string filePath = Path.Combine(m_VideoParameter.CapturePath, dateStr, fileName + ".jpg");
                if (!File.Exists(filePath))
                    return;
                int width = this.pbVideoShow.Width;
                int height = this.pbVideoShow.Height;
                this.pbVideoCapture.Location = new Point(width / 2, height / 2);
                this.pbVideoCapture.Size = new Size(width / 2, height / 2);
                this.pbVideoCapture.Visible = true;
                this.pbVideoCapture.Image = Image.FromFile(filePath);
            }
        }

        public void CapturePic(string fileName)
        {
            try
            {
                if (m_VideoParameter.VideoType == 0)
                {
                    if (m_RealHandle < 0)
                    {
                        LogHelper.info(fileName + "抓拍视频时未预览!");
                        return;
                    }
                    //设置抓拍图片格式
                    if (CHCNetSDK.NET_DVR_SetCapturePictureMode(CHCNetSDK.CAPTURE_MODE.JPEG_MODE))
                    {
                        string dateStr = DateTime.Now.ToString("yyyyMMdd");
                        string dirPath = Path.Combine(m_VideoParameter.CapturePath, dateStr);
                        if (!Directory.Exists(dirPath))
                            Directory.CreateDirectory(dirPath);
                        string filePath = Path.Combine(dirPath, fileName + ".jpg");
                        if (!CHCNetSDK.NET_DVR_CapturePicture(m_RealHandle, filePath))
                        {
                            LogHelper.info(fileName + "抓拍视频错误，错误代码为" + CHCNetSDK.NET_DVR_GetLastError().ToString());
                        }
                    }
                    else
                    {
                        LogHelper.info(fileName + "抓拍视频设置图片格式错误，错误代码为" + CHCNetSDK.NET_DVR_GetLastError().ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("抓图异常：" + ex.Message);
            }
        }

        public void CloseCapture()
        {
            this.pbVideoCapture.Visible = false;
        }

        public void SetUnUseVideo()
        {
            btnOpen.Enabled = false;
            btnClose.Enabled = false;
            lcgFGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
            lcgBGate.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
        }
        #endregion

        #region 按钮事件
        private void btnOpen_Click(object sender, EventArgs e)
        {
            //不同的视频设备打开方式不同，目前两种打开方式一个有信道，一种没有信道
            if (m_VideoParameter.VideoType == 0)
            {
                if (!OpenVideoByHK())
                    return;
            }
            else if (m_VideoParameter.VideoType == 1)
            {
                if (!OpenVideoSecondWay())
                    return;
            }
            btnOpen.Enabled = false;
            btnClose.Enabled = true;
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            string errInfo = "";
            if (m_VideoParameter.VideoType == 0)
                errInfo = CloseVideoFirstWay();
            else if (m_VideoParameter.VideoType == 1)
                errInfo = CloseVideoSecondWay();
            if (!string.IsNullOrEmpty(errInfo))
            {
                MessageBox.Show(errInfo);
                return;
            }
            btnOpen.Enabled = true;
            btnClose.Enabled = false;
        }

        private void btnFGateUp_Click(object sender, EventArgs e)
        {
            try
            {
                if (m_GateControlParameter.GateControlWay == 0)
                {
                    SetRedGreen(m_GateControlParameter.FGateUp, true);
                    System.Threading.Thread.Sleep(50);
                    SetRedGreen(m_GateControlParameter.FGateUp, false);
                }
                else
                {
                    setIO(m_AdamSocket, m_GateControlParameter.FGateUp, 1);
                    System.Threading.Thread.Sleep(100);
                    setIO(m_AdamSocket, m_GateControlParameter.FGateUp, 0);
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("前道闸抬起异常：" + ex.Message);
            } 
        }

        private void btnFGateDown_Click(object sender, EventArgs e)
        {
            try
            {
                if (m_GateControlParameter.GateControlWay == 0)
                {
                    SetRedGreen(m_GateControlParameter.FGateDown, true);
                    System.Threading.Thread.Sleep(50);
                    SetRedGreen(m_GateControlParameter.FGateDown, false);
                }
                else
                {
                    setIO(m_AdamSocket, m_GateControlParameter.FGateDown, 1);
                    System.Threading.Thread.Sleep(100);
                    setIO(m_AdamSocket, m_GateControlParameter.FGateDown, 0);
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("前道闸放下异常：" + ex.Message);
            } 
        }

        private void btnBGateUp_Click(object sender, EventArgs e)
        {
            try
            {
                if (m_GateControlParameter.GateControlWay == 0)
                {
                    SetRedGreen(m_GateControlParameter.BGateUp, true);
                    System.Threading.Thread.Sleep(50);
                    SetRedGreen(m_GateControlParameter.BGateUp, false);
                }
                else
                {
                    setIO(m_AdamSocket, m_GateControlParameter.BGateUp, 1);
                    System.Threading.Thread.Sleep(100);
                    setIO(m_AdamSocket, m_GateControlParameter.BGateUp, 0);
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("后道闸抬起异常：" + ex.Message);
            } 
        }

        private void btnBGateDown_Click(object sender, EventArgs e)
        {
            try
            {
                if (m_GateControlParameter.GateControlWay == 0)
                {
                    SetRedGreen(m_GateControlParameter.BGateDown, true);
                    System.Threading.Thread.Sleep(50);
                    SetRedGreen(m_GateControlParameter.BGateDown, false);
                }
                else
                {
                    setIO(m_AdamSocket, m_GateControlParameter.BGateDown, 1);
                    System.Threading.Thread.Sleep(100);
                    setIO(m_AdamSocket, m_GateControlParameter.BGateDown, 0);
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("后道闸放下异常：" + ex.Message);
            } 
        }
        #endregion

        #region 私有方法
        #region 视频相关
        //海康威视视频初始化
        private void InitVideoDevice()
        {
            m_IsInitVideoSDK = CHCNetSDK.NET_DVR_Init();
            if (m_IsInitVideoSDK == false)
            {
                MessageBox.Show("视频组件初始化失败!");
                return;
            }
            else
            {
                //保存SDK日志 To save the SDK log
                CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
                for (int i = 0; i < 64; i++)
                {
                    m_ChannelNumArr[i] = -1;
                }
            }
        }

        //海康威视预览视频
        //一种视频操作，如金塔
        private bool OpenVideoByHK()
        {
            string errInfo = "";
            errInfo = LoginVideo();
            //登录视频
            if (!string.IsNullOrEmpty(errInfo))
            {
                MessageBox.Show(errInfo);
                return false;
            }
            errInfo = ViewVideo();
            //预览视频
            if (!string.IsNullOrEmpty(errInfo))
            {
                MessageBox.Show(errInfo);
                return false;
            }
            return true;
        }

        //登录视频，如返回空字符串则登录成功，反之失败
        private string LoginVideo()
        {
            string errInfo = "";
            try
            {
                m_UserID = CHCNetSDK.NET_DVR_Login_V30(m_VideoParameter.VideoIP, m_VideoParameter.VideoPort,
                    m_VideoParameter.VideoUser, m_VideoParameter.VideoPassword, ref m_VideoDeviceInfo);
            }
            catch (Exception ex)
            {
                errInfo = "登录视频失败:" + ex.Message;
                LogHelper.error(errInfo);
            }
            if (m_UserID < 0)
            {
                uint lastErrCode = CHCNetSDK.NET_DVR_GetLastError();
                //登录失败，输出错误号 Failed to login and output the error code
                errInfo = "NET_DVR_Login_V30 failed, error code= " + lastErrCode;
                LogHelper.error(errInfo);
            }
            else
            {
                //登录成功
                uint dwAChanTotalNum = (uint)m_VideoDeviceInfo.byChanNum;
                if (m_VideoDeviceInfo.byIPChanNum > 0)
                {
                    //InfoIPChannel();
                }
                else
                {
                    for (int i = 0; i < dwAChanTotalNum; i++)
                    {
                        m_ChannelNumArr[i] = i + (int)m_VideoDeviceInfo.byStartChan;
                    }
                }
            }
            return errInfo;
        }

        //预览视频
        private string ViewVideo()
        {
            string errInfo = "";
            if (m_RealHandle < 0)
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.hPlayWnd = pbVideoShow.Handle;//预览窗口 live view window
                lpPreviewInfo.lChannel = m_ChannelNumArr[0];//预览的设备通道 the device channel number
                lpPreviewInfo.dwStreamType = 0;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = true; //0- 非阻塞取流，1- 阻塞取流
                IntPtr pUser = IntPtr.Zero;//用户数据 user data 
                if (0 == 0)//直接预览
                {
                    try
                    {
                        //打开预览 Start live view 
                        m_RealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_UserID, ref lpPreviewInfo, null/*RealData*/, pUser);
                    }
                    catch (Exception ex)
                    {
                        errInfo = "预览视频失败：" + ex.Message;
                        LogHelper.error(errInfo);
                    }
                }
            }
            return errInfo;
        }

        public int WM_COMMAND;
        public int WM_USER = 0x0400;
        //另一种视频处理方式，如惠塔
        private bool OpenVideoSecondWay()
        {
            WM_COMMAND = WM_USER + 2;

            CHANNEL_CLIENTINFO info = new CHANNEL_CLIENTINFO();
            info.m_buffnum = 50;
            info.m_ch = 0;

            info.m_hVideohWnd = this.pbVideoShow.Handle;//绑定picturebox 事件
            info.m_hChMsgWnd = IntPtr.Zero;    //
            info.m_nChmsgid = 0;              //

            string ip = m_VideoParameter.VideoIP;//IP地址
            short port = (short)m_VideoParameter.VideoPort;//端口
            string password = m_VideoParameter.VideoPassword;
            string user = m_VideoParameter.VideoUser;
            short ch = m_VideoParameter.VideoChannel;//信道

            info.m_sername = "video server";//服务器名
            info.m_username = user;//用户名
            info.m_password = password;//密码
            info.m_playstart = 1;            //Play
            info.m_tranType = 3;             //TCP
            info.m_useoverlay = 0;
            info.url = ip;//IP地址
            info.m_ch = Convert.ToByte(ch);//信道数
            info.callback = msgCallbk;

            int iSizeOfStruct = Marshal.SizeOf(typeof(CHANNEL_CLIENTINFO));
            IntPtr pStructChannel = Marshal.AllocHGlobal(iSizeOfStruct);
            Marshal.StructureToPtr(info, pStructChannel, false);

            bool flag = LauInterop.VSNET_ClientStartup((uint)WM_COMMAND, IntPtr.Zero, null, IntPtr.Zero, IntPtr.Zero);
            if (flag == false)
            {
                MessageBox.Show("启动失败");//Could not start SDK
                return false;
            }
            if (m_RealHandle > 0)
            {
                LauInterop.VSNET_ClientStop(m_RealHandle);
                m_RealHandle = -1;
            }
            m_RealHandle = LauInterop.VSNET_ClientStart(ip, pStructChannel, port, 0);
            if (m_RealHandle == -1)
            {
                MessageBox.Show("无法连接到摄像头");//Could not connect to camera"
                return false;
            }
            return true;
        }

        public const int LAUMSG_LINKMSG = 1;
        public const int LAUMSG_VIDEOMOTION = 2;
        public const int LAUMSG_VIDEOLOST = 3;
        public const int LAUMSG_ALARM = 4;
        public const int LAUMSG_OUTPUTSTATUS = 5;
        public const int LAUMSG_CURSWITCHCHAN = 6;
        public const int LAUMSG_HIDEALARM = 7;

        public static void messagecallback(IntPtr hHandle, int wParam, int lParam, IntPtr context)
        {
            switch (wParam)
            {
                case LAUMSG_LINKMSG:
                    {
                        //link message
                        if (lParam == 0)
                        {
                            Trace.WriteLine("connect successful\n");
                            //VSNET_ClientStartMp4Capture(hHandle, "rec.mp4");
                            //VSNET_ClientStartNomalCap(hHandle, Nomalvideo, NULL, NomalAudio, NULL);
                        }
                        else if (lParam == 1)
                        {
                            Trace.WriteLine("user stop connect\n");
                        }
                        else if (lParam == 2)
                        {
                            Trace.WriteLine("connect failed\n");
                        }
                        else if (lParam == 3)
                        {
                            Trace.WriteLine("connect dislinked\n");
                        }
                        else if (lParam == 4)
                        {
                            Trace.WriteLine("port assert\n");
                        }
                        else if (lParam == 5)
                        {
                            Trace.WriteLine("memory assign failed\n");
                        }
                        else if (lParam == 6)
                        {
                            Trace.WriteLine("connect dns failed\n");
                        }
                        else if (lParam == -102)
                        {
                            Trace.WriteLine("username or password wrong\n");
                        }
                        else if (lParam == -103)
                        {
                            Trace.WriteLine("system user full\n");
                        }
                        else if (lParam == -105)
                        {
                            Trace.WriteLine("channel user full\n");
                        }
                        else if (lParam == -106)
                        {
                            Trace.WriteLine("no such channel\n");
                        }
                        else if (lParam == -112)
                        {
                            Trace.WriteLine("not find server\n");
                        }
                        else
                        {
                            Trace.WriteLine(" No define~! \n");
                        }
                        break;
                    }
                case LAUMSG_VIDEOMOTION:
                    Trace.WriteLine("video motion alarm\n");
                    break;
                case LAUMSG_VIDEOLOST:
                    Trace.WriteLine("video lost alarm\n");
                    break;
                case LAUMSG_ALARM:
                    {
                        Trace.WriteLine("sensor alarm\n");
                        break;
                    }
                case LAUMSG_OUTPUTSTATUS:
                    Trace.WriteLine("alarmout status\n");
                    break;
                case LAUMSG_CURSWITCHCHAN:
                    Trace.WriteLine("curswitch\n");
                    break;
                case LAUMSG_HIDEALARM:
                    Trace.WriteLine("video hiden alarm\n");
                    break;
                default:
                    Trace.WriteLine(" No define~! \n");
                    break;
            }
        }
        static m_messagecallback msgCallbk = new m_messagecallback(messagecallback);

        private string CloseVideoFirstWay()
        {
            string errInfo = "";
            //停止预览
            if (m_RealHandle >= 0)
            {
                try
                {
                    CHCNetSDK.NET_DVR_StopRealPlay(m_RealHandle);
                }
                catch (Exception ex)
                {
                    errInfo = "停止预览视频失败：" + ex.Message;
                    LogHelper.error(errInfo);
                }
                m_RealHandle = -1;
            }
            //注销登录
            if (m_UserID >= 0)
            {
                try
                {
                    CHCNetSDK.NET_DVR_Logout(m_UserID);
                }
                catch (Exception ex)
                {
                    errInfo = "停止登录视频失败：" + ex.Message;
                    LogHelper.error(errInfo);
                }
                m_UserID = -1;
            }
            CHCNetSDK.NET_DVR_Cleanup();
            InitVideoDevice();
            this.pbVideoShow.Refresh();
            return errInfo;
        }

        private string CloseVideoSecondWay()
        {
            string errInfo = "";

            if (m_RealHandle >= 0)
            {
                try
                {
                    LauInterop.VSNET_ClientStop(m_RealHandle);
                    LauInterop.VSNET_ClientCleanup();
                }
                catch (Exception ex)
                {
                    errInfo = "停止登录视频失败：" + ex.Message;
                    LogHelper.error(errInfo);
                }
                m_RealHandle = -1;
            }
            this.pbVideoShow.Refresh();
            return errInfo;
        }
        #endregion

        #region 道闸相关
        //板卡IO控制道闸
        private void SetRedGreen(int point, bool mode)//控制io开关
        {
            long RedGreen = PCIControl.Getfeatures();
            string status = PCIHelper.RedGreenValue(RedGreen);
            int x = mode == true ? 1 : 0;
            if (status.Substring(point, 1) == x.ToString())
            {

            }
            else
            {
                long b = PCIControl.UpdateLED1(point, mode);
            }
        }

        //IO控制
        private void setIO(AdamSocket io, int port, int OnOrOff)
        {
            System.Threading.Thread.Sleep(30);
            io.Modbus().ForceSingleCoil(port, OnOrOff);
            System.Threading.Thread.Sleep(30);
            io.Modbus().ForceSingleCoil(port, OnOrOff);
        }
        #endregion
        #endregion

        private void timer_Clean_Tick(object sender, EventArgs e)
        {
            try
            {
                if (m_VideoParameter.VideoChannel == -1)
                {
                    //停止预览
                    if (m_RealHandle >= 0)
                    {
                        CHCNetSDK.NET_DVR_StopRealPlay(m_RealHandle);
                        m_RealHandle = -1;
                    }

                    //注销登录
                    if (m_UserID >= 0)
                    {
                        CHCNetSDK.NET_DVR_Logout(m_UserID);
                        m_UserID = -1;
                    }
                    CHCNetSDK.NET_DVR_Cleanup();
                    InitVideoDevice();
                    btnOpen_Click(null, null);
                }
                else
                {
                    if (m_RealHandle >= 0)
                    {
                        LauInterop.VSNET_ClientStop(m_RealHandle);
                        LauInterop.VSNET_ClientCleanup();
                        m_RealHandle = -1;
                        btnOpen_Click(null, null);
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.error("清理视频缓存错误：" + ex.Message);
            }
        }

        private void timer_IOStatus_Tick(object sender, EventArgs e)
        {
            bool[] bDiData;
            m_AdamSocket.Modbus().ReadCoilStatus(1, 6, out bDiData);
        }
    }
}
